package com.yonyou.ucf.mdd.ext.util.schema;

import com.yonyou.cloud.utils.CollectionUtils;
import com.yonyou.ucf.mdd.common.exceptions.message.MddIllegalArgumentMsgException;
import com.yonyou.ucf.mdd.common.exceptions.message.MsgExceptionCode;
import com.yonyou.ucf.mdd.ext.util.dbutils.DbMetaData;
import com.yonyou.ucf.mdd.ext.util.dbutils.MddExtDbUtil;
import com.yonyou.ucf.mdd.ext.util.localcache.AbstractSystemCacheUtil;
import com.yonyou.ucf.mdd.ext.util.localcache.DbSchemaCacheUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @date：2020/10/20
 * @author:王松
 * @email: 13718938509@139.com
 */
public class DbSchemaUtil {
    private static final Logger logger = LoggerFactory.getLogger(DbSchemaUtil.class);
    private static final String TABLE_MENU_LANG_DESC = " select  *  from %s where 1<> 1 ";
    private static final int SNOW_ID_MIN_LEN = 16;
    private static final Map<String, Integer> cacheColumnSize = new HashMap<>();
    public static AbstractSystemCacheUtil cache;

    static {
        cache = DbSchemaCacheUtil.getInstance();
    }

    /**
     * 检查表是否存在
     *
     * @param tableName
     * @return
     * @throws Exception
     */
    public static boolean checkTable(String tableName) throws Exception {
        Boolean isExists = cache.get(tableName.toUpperCase());
        if (null == isExists) {
            return setCache(tableName);
        }
        return isExists.booleanValue();
    }

    public static boolean checkTableFromMetaDb(String tableName) throws Exception {
        String dbName = "meta";
        return checkTableFromMetaDb(dbName,tableName);
    }


    public static boolean checkTableFromMetaDb(String dbName, String tableName) throws Exception {
        String key = String.format("%s#%s",dbName,tableName.toUpperCase());
        Boolean isExists = cache.get(key);
        if (null == isExists) {
            return setCache(dbName, tableName);
        }
        return isExists.booleanValue();
    }

    /**
     * 查询表中指定列是否存在
     *
     * @param tableName
     * @param columnName
     * @return
     * @throws Exception
     */
    public static boolean checkTableAndColumn(String tableName, String columnName) throws Exception {
        return checkTableAndColumn(null,tableName,columnName);
    }

    /**
     * 查询表中指定列是否存在
     *
     * @param tableName
     * @param columnName
     * @return
     * @throws Exception
     */
    public static boolean checkTableAndColumn(String dbName,String tableName, String columnName) throws Exception {
        Boolean isExists = cache.get((tableName + "_" + columnName).toUpperCase());
        if (null == isExists) {
            return setCache(dbName,tableName, columnName);
        }
        return isExists.booleanValue();
    }
    /**
     * id 是否支持雪花算法
     *
     * @param tableName
     * @return
     */
    public static boolean supportSnowId(String tableName) {
        int length = getLengthIdColumn(tableName);
        if (length >= SNOW_ID_MIN_LEN) {
            return true;
        }
        return false;
    }

    /**
     * 获得id列长度
     *
     * @param tableName 表名
     * @return
     */
    public static int getLengthIdColumn(String tableName) {
        return getLengthColumn(tableName, "ID");
    }

    /**
     * 获得表指定列的长度
     *
     * @param tableName 表名
     * @param columnName 列名
     * @return
     */
    public static int getLengthColumn(String tableName, String columnName) {
        if (StringUtils.isEmpty(tableName) || StringUtils.isEmpty(columnName)) {
            //"表名或列名不允许为空"
            throw new MddIllegalArgumentMsgException(MsgExceptionCode.PARAM_ISNULL);
        }
        String cacheKey = tableName.toUpperCase() + "_" + columnName.toUpperCase();
        Integer size = cacheColumnSize.get(cacheKey);
        if (null != size && size != 0) {
            return size;
        }
        String queryTableSql = String.format(TABLE_MENU_LANG_DESC, tableName);
        List<Map<String, DbMetaData>> resultMapList = MddExtDbUtil.getMetaData(queryTableSql);
        if (CollectionUtils.isEmpty(resultMapList)) {
            throw new RuntimeException("列查询异常" + queryTableSql);
        }
        Map<String, DbMetaData> metaDataMap = resultMapList.get(0);
        DbMetaData mddMetaData = metaDataMap.get(columnName.toUpperCase());
        if (null != mddMetaData) {
            return mddMetaData.getLength();
        }
        return 0;
    }

    /**
     * 设置数据缓存
     *
     * @param tableName
     * @return
     * @throws Exception
     */
    private static boolean setCache(String tableName) throws Exception {

        Boolean isExists = cache.get(tableName.toUpperCase());
        if (null != isExists) {
            return isExists.booleanValue();
        }

        isExists = checkTableExists(tableName);
        if (isExists) {
            cache.put(tableName.toUpperCase(), isExists);
        }

        return isExists.booleanValue();
    }
    private static boolean setCache(String dbName, String tableName) throws Exception {
        String key = String.format("%s#%s",dbName,tableName.toUpperCase());
        Boolean isExists = cache.get(key);
        if (null != isExists) {
            return isExists.booleanValue();
        }

        isExists = checkTableExists(dbName, tableName);
        if (isExists) {
            cache.put(key, isExists);
        }

        return isExists.booleanValue();
    }

    private static boolean setCache(String dbName,String tableName, String columnName) throws Exception {
        Boolean isExists = cache.get((tableName + "_" + columnName).toUpperCase());
        if (null != isExists) {
            return isExists.booleanValue();
        }
        isExists = checkTableAndColumnExists(dbName,tableName, columnName);
        if (isExists) {
            cache.put((tableName + "_" + columnName).toUpperCase(), isExists);
        }
        return isExists;
    }

    /**
     * 检查表是否存在
     *
     * @param tableName
     * @return
     * @throws Exception
     */
    private static boolean checkTableExists(String tableName) throws Exception {
        try {
            String queryTableSql = String.format(TABLE_MENU_LANG_DESC, tableName);
            MddExtDbUtil.executeUiMetaSql(queryTableSql);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
    private static boolean checkTableExists(String dbName, String tableName) throws Exception {
        try {
            String queryTableSql = String.format(TABLE_MENU_LANG_DESC, tableName);
            MddExtDbUtil.executeUiMetaSql(dbName, queryTableSql,null);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获得表所有列(mysql)
     *
     * @param tableName 表名
     * @return  Map<String, Boolean> String 列名，boolean 是否允许为空
     * @throws Exception
     */
    public static Map<String, DbMetaData> getTableColumn(String tableName) throws Exception {
        try {
            String queryTableSql = String.format(TABLE_MENU_LANG_DESC, tableName);
            List<Map<String, DbMetaData>> columnMap = MddExtDbUtil.getMetaData(queryTableSql);
            if (CollectionUtils.isEmpty(columnMap)) {
                throw new Exception("列查询异常" + queryTableSql);
            }
            return columnMap.get(0);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }


    public static boolean checkTableAndColumnExists(String tableName, String columnName) throws Exception{
        return checkTableAndColumnExists(null,tableName,columnName);
    }
    /**
     * 检查表中某列是否存在
     *
     * @param tableName
     * @param columnName
     * @return
     * @throws Exception
     */
    public static boolean checkTableAndColumnExists(String dbNameSource,String tableName, String columnName) throws Exception {
        String queryTableSql = String.format(TABLE_MENU_LANG_DESC, tableName);
        //check table is exists
        try {
            List<Map<String, DbMetaData>> resultMapList = MddExtDbUtil.getMetaData(dbNameSource,queryTableSql);
            if (CollectionUtils.isEmpty(resultMapList)) {
                throw new Exception("列查询异常" + queryTableSql);
            }
            Map metaDataMap = resultMapList.get(0);
            if (null != metaDataMap.get(columnName.toUpperCase())) {
                return true;
            }
            return false;
        } catch (Exception e) {
//            logger.error(e.getMessage(), e);
            throw new Exception("表查询异常" + queryTableSql);
        }
    }
}
